package com.mrl.stack;

/**
 * 使用两个栈实现表达式的解析
 * @author 正义君
 * @version 1.0
 */
public class Calc {
    public static void main(String[] args) {
        // 创建数栈和符号栈
        CalcStack numStack = new CalcStack(20);
        CalcStack operStack = new CalcStack(20);
        // 创建基础变量
        int num1;
        int num2;
        char oper;
        int c;
        String keepNum;
        int index = 0;
        String expression = "1+2+3+4*2";

        while (expression.length() != index) {
            // 取出当前字符
            c = expression.substring(index, index + 1).charAt(0);
            if (operStack.isOper(c)) {
                // 如果是操作符
                if (!operStack.isEmpty()) {
                    // 栈内不为空
                    if (operStack.priority(c) <= operStack.priority(operStack.get())) {
                        // 操作符比栈内优先级高
                        // 如果当前运算符小于栈顶运算符则计算
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                        oper = (char) operStack.pop();
                        numStack.push(numStack.calc(num1, num2, oper));
                        operStack.push(c);
                    } else {
                        // 操作符比栈内优先级低
                        operStack.push(c);
                    }
                } else {
                    // 栈内为空
                    operStack.push(c);
                }
            } else {
                // 如果是数字
                // 直接加入数栈
                numStack.push(c - 48);
            }
            index ++;
        }

        while (!operStack.isEmpty()) {
            num1 = numStack.pop();
            num2 = numStack.pop();
            oper = (char) operStack.pop();
            numStack.push(numStack.calc(num1, num2, oper));
        }

        System.out.println("结果为:" + numStack.pop());
    }
}

class CalcStack {
    // 栈
    private final int[] obj;
    // 栈顶
    private int top = -1;
    // 栈的大小
    private int size;

    /**
     * 构造器，创建一个大小为size的栈
     * @param size 栈的大小
     */
    CalcStack(int size) {
        obj = new int[size];
        this.size = size;
    }

    /**
     * 构造器，创建一个大小为20的栈
     */
    CalcStack() {
        obj = new int[20];
        this.size = 20;
    }

    /**
     * 判断栈是否满
     * @return 满为 true 否则为 false
     */
    public boolean isFull() {
        return top >= size - 1;
    }

    /**
     * 判断栈是否为空
     * @return 空为 true 否则为 false
     */
    public boolean isEmpty() {
        return top == -1;
    }

    /**
     * 向栈内加入一个元素  压栈
     * @param object 加入栈的对象
     */
    public void push(int object) {
        if (isFull()) {
            throw new RuntimeException("当前栈已满");
        }
        top ++;
        obj[top] = object;
    }

    /**
     * 从栈中取出一个元素  弹栈
     * @return 返回栈顶的一个元素
     */
    public int pop() {
        if (isEmpty()) {
            throw new RuntimeException("栈空");
        }
        return obj[top--];
    }

    /**
     * 查询栈的大小
     * @return 返回一个栈的长度
     */
    public int size() {
        return size;
    }

    /**
     * 获取栈顶元素，但不取出
     * @return 返回栈顶元素
     */
    public int get() {
        if (isEmpty()) {
            throw new RuntimeException("栈空");
        }
        return obj[top];
    }

    /**
     * 显示栈的内容
     */
    public void list() {
        if (isEmpty()) {
            throw new RuntimeException("栈空");
        }
        for (int i = top;i >= 0;i--) {
            System.out.printf("stack[%d]=%s\n", i, obj[i]);
        }
    }

    /**
     * 判断是否为操作符
     * @param i 待判断的字符
     * @return 为操作符返回 true 否则返回 false
     */
    public boolean isOper(int i) {
        return i == '+' || i == '-' || i == '*' || i == '/';
    }

    /**
     * 判断符号优先级
     * @param i 输入的符号
     * @return 返回优先级，值越大说明优先级越高
     */
    public int priority(int i) {
        switch (i) {
            case '+':
            case '-':
                return 1;
            case '*':
            case '/':
                return 2;
        }
        return 0;
    }

    /**
     * 计算数据
     * @param num1 第一数据
     * @param num2 第二数据
     * @param oper 操作符
     * @return 返回计算结果
     */
    public int calc(int num1, int num2, char oper) {
        switch (oper) {
            case '+':
                return num1 + num2;
            case '-':
                return num2 - num1;
            case '*':
                return num1 * num2;
            case '/':
                return num2 / num1;
            default:
                return 0;
        }
    }
}
